<?php

namespace dux;

class Engine {

    protected static $classes = array();

    public function __construct() {
        $this->init();
    }

    /**
     * 初始化
     */
    public function init() {
        $this->autoload();
        $this->handleErrors();
        $this->route();
    }

    /**
     * 注册类
     */
    public function autoload() {
        spl_autoload_register(array(__CLASS__, 'loadClass'));
    }

    /**
     * 加载类文件
     * @param $class
     * @return bool
     */
    public function loadClass($class) {
        $classFile = str_replace(array('\\', '_'), '/', $class) . '.php';
        $file = ROOT_PATH . '/' . $classFile;
        if (!isset(self::$classes[$file])) {
            if (!file_exists($file)) {
                return false;
            }
            self::$classes[$classFile] = $classFile;
            require_once $classFile;
        }
        return true;
    }

    /**
     * 结果异常错误
     */
    public function handleErrors() {
        set_error_handler(array($this, 'handleError'));
        set_exception_handler(array($this, 'handleException'));
        return;
        if (class_exists('\Whoops\Run')) {
            $errorPage = new \Whoops\Handler\PrettyPageHandler();
            $errorPage->setEditor("phpstorm");
            $errorPage->setPageTitle("DuxCmf Internal Server Error");
            $whoops = new \Whoops\Run;
            $whoops->pushHandler($errorPage);
            $whoops->register();
        } else {
            set_error_handler(array($this, 'handleError'));
            set_exception_handler(array($this, 'handleException'));
        }
    }

    /**
     * 错误接管
     * @param $errno
     * @param $errstr
     * @param $errfile
     * @param $errline
     * @throws \ErrorException
     */
    public function handleError($errno, $errstr, $errfile, $errline) {
        if ($errno & error_reporting()) {
            throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
        }
    }

    /**
     * 异常接管
     * @param $e
     */
    public function handleException($e) {
        if (\Config::get('dux.log')) {
            error_log("{$e->getMessage()} line {$e->getLine()} in file {$e->getFile()}");
        }
        $html = "<title>Dux System Engine</title>";
        if (!\Config::get('dux.debug')) {
            $html .= "<h1>500 Internal Server Error</h1>";
        } else {
            $html .= "<h1>{$e->getMessage()}</h1>";
            $html .= "<code>line {$e->getLine()} in file {$e->getFile()}</code>";
            $html .= "<p>";
            foreach ($e->getTrace() as $value) {
                $html .= "{$value['file']} line {$value['line']} <br>";
            }
            $html .= "</p>";
        }
        $html .= "<p> run time " . \Dux::runTime() . "s</p>";
        \Dux::header(500, $html);
    }

    /**
     * 解析路由
     */
    public function route() {
        $url = str_replace(ROOT_SCRIPT, '', $_SERVER['REQUEST_URI']);
        $url = trim($url, '/');
        $urlParse = parse_url($url);
        $urlPath = explode('.', $urlParse['path'], 2);
        $urlArray = explode("/", $urlPath[0], 4);
        $urlCount = count($urlArray);
        $moduleRule = array_flip(\Config::get('dux.module'));
        $roleName = '';
        if ($urlCount >= 4) {
            $roleName = $urlArray[0];
            $layer = $moduleRule[$urlArray[0]];
        } else {
            foreach($moduleRule as $key => $vo) {
                if(empty($key)) {
                    $layer = $vo;
                }
            }
            if(empty($layer)) {
                $layer = reset($moduleRule);
            }
        }

        if ($urlCount >= 4) {
            $urlArray = explode("/", $urlPath[0], 5);
            $appName = empty($urlArray[1]) ? 'index' : $urlArray[1];
            $modelName = empty($urlArray[2]) ? 'index' : $urlArray[2];
            $actionName = empty($urlArray[3]) ? 'index' : $urlArray[3];
            $params = $urlArray[4];
        }else{
            $appName = empty($urlArray[0]) ? 'index' : $urlArray[0];
            $modelName = empty($urlArray[1]) ? 'index' : $urlArray[1];
            $actionName = empty($urlArray[2]) ? 'index' : $urlArray[2];
            $params = $urlArray[3];
        }

        $paramArray = explode("/", $params);

        if (!defined('ROLE_NAME')) define('ROLE_NAME', $roleName);
        if (!defined('LAYER_NAME')) define('LAYER_NAME', $layer);
        if (!defined('APP_NAME')) define('APP_NAME', strtolower($appName));
        if (!defined('MODULE_NAME')) define('MODULE_NAME', ucfirst($modelName));
        if (!defined('ACTION_NAME')) define('ACTION_NAME', $actionName);
        if (empty($paramArray)) return;
        foreach ($paramArray as $key => $value) {
            $list = explode('-', $value, 2);
            if (count($list) == 2) {
                $_GET[$list[0]] = $list[1];
            }
        }
    }

    /**
     * 运行框架
     * @throws \Exception
     */
    public function run() {
        $class = '\app\\' . APP_NAME . '\\'. LAYER_NAME .'\\' . MODULE_NAME . ucfirst(LAYER_NAME);
        $action = ACTION_NAME;
        if (!class_exists($class)) {
            if (!\Config::get('dux.debug')) {
                \Dux::notFound();
            } else {
                throw new \Exception("Class '{$class}' not found", 500);
            }
        }
        $obj = new $class();
        if (!method_exists($class, $action)) {
            if (!\Config::get('dux.debug')) {
                \Dux::notFound();
            } else {
                throw new \Exception("Action '{$class}::{$action}()' not found", 500);
            }
        }
        $obj->$action();
    }
}